home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Sprite 1984 - 1993
/
Sprite 1984 - 1993.iso
/
src
/
kernel
/
net
/
ds5000.md
/
netDFXmit.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-12-18
|
30KB
|
1,041 lines
/*
* netDFXmit.c --
*
* Routines to transmit packets on the DEC 700 FDDI controller.
*
* Copyright 1992 Regents of the University of California
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
* fee is hereby granted, provided that the above copyright
* notice appear in all copies. The University of California
* makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without
* express or implied warranty.
*
*/
#ifndef lint
static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/net/ds5000.md/netDFXmit.c,v 1.2 92/06/08 22:46:03 jhh Exp $";
#endif
#include <sprite.h>
#include <sys.h>
#include <netDFInt.h>
#include <vm.h>
#include <vmMach.h>
#include <list.h>
#include <sync.h>
#include <machMon.h>
#include <dbg.h>
/*
* Macros to step RMC XMT ring pointers.
*/
#define NEXT_RMC_SEND(p) ( (((p)+1) > statePtr->rmcXmtLastDescPtr) ? \
statePtr->rmcXmtFirstDescPtr : \
((p)+1))
#define PREV_RMC_SEND(p) ( (((p)-1) < statePtr->rmcXmtFirstDescPtr) ? \
statePtr->rmcXmtLastDescPtr : \
((p)-1))
/*
* Macros to step SMT XMT ring pointers.
*/
#define NEXT_SMT_SEND(p) ( (((p)+1) > statePtr->smtXmtLastDescPtr) ? \
statePtr->smtXmtFirstDescPtr : \
((p)+1))
static ReturnStatus OutputPacket _ARGS_((Net_FDDHdr *fddiHdrPtr,
Net_ScatterGather *scatterGatherPtr,
int scatterGatherLength,
NetDFState *statePtr));
/*
* To access the buffer corresponding to the RMC XMT descriptor
*/
#define RmcXmtBufFromDesc(statePtr, descPtr) \
(statePtr->rmcXmtFirstBufPtr + \
(unsigned long)(descPtr - statePtr->rmcXmtFirstDescPtr))
/*
*----------------------------------------------------------------------
*
* NetDFBcopy --
*
* Just like bcopy(), except that all data is transfered in words
* on word-aligned boundaries. The adapter requires that this
* be so.
*
* Results:
* None.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
void
NetDFBcopy(startPtr, destPtr, numBytes)
unsigned char *startPtr;
unsigned char *destPtr;
unsigned long numBytes;
{
register unsigned char *bytePtr, *toPtr, *fromPtr;
register unsigned long *div;
register unsigned long mod, length, aligned;
register unsigned long n;
unsigned long value;
/*
* One of the most annoying things about this adapter is that,
* although you can read bytes, you can't write bytes that
* are not word-aligned. This is a pain, because we can't just
* flat out use bcopy()...we have to massage the beginnings and
* ends of the buffers so that we use bcopy only on an integral
* number of words.
*/
fromPtr = startPtr;
toPtr = destPtr;
length = numBytes;
if (length == 0) {
return;
}
mod = (unsigned long)toPtr % sizeof(unsigned long);
div = (unsigned long *)(((unsigned long)toPtr >> 2) << 2);
/*
* Write bytes to the destination array until the pointer
* is word-aligned.
*/
value = *div;
bytePtr = (unsigned char *)&value;
switch((int)mod) {
case 1:
bytePtr[1] = fromPtr[0];
fromPtr++;
case 2:
bytePtr[2] = fromPtr[0];
fromPtr++;
case 3:
bytePtr[3] = fromPtr[0];
fromPtr++;
*div = value;
length -= (4 - mod);
toPtr += (4 - mod);
default:
break;
}
aligned = (length >> 2) << 2;
/*
* We are really hosed if the source buffer is not word aligned
* after we align the dest buffer. The adapter write addressing
* really stinks. Luckily this appears to be a rare occurance.
*/
mod = (unsigned long)fromPtr % sizeof(unsigned long);
if (mod) {
n = aligned;
div = (unsigned long *)toPtr;
while (n > 0) {
value = *div;
bytePtr = (unsigned char *)&value;
bytePtr[0] = fromPtr[0];
bytePtr[1] = fromPtr[1];
bytePtr[2] = fromPtr[2];
bytePtr[3] = fromPtr[3];
*div = value;
div++;
fromPtr += 4;
n -= 4;
}
toPtr += aligned;
} else {
/*
* Only bcopy() an integral number of words.
*/
if (aligned != 0) {
bcopy(fromPtr, toPtr, aligned);
toPtr += aligned;
fromPtr += aligned;
}
}
/*
* finish up the tail end of the buffers
*/
if (aligned != length) {
mod = length - aligned;
div = (unsigned long *)toPtr;
value = *div;
bytePtr = (unsigned char *)&value;
switch((int)mod) {
case 3:
bytePtr[2] = fromPtr[2];
case 2:
bytePtr[1] = fromPtr[1];
case 1:
bytePtr[0] = fromPtr[0];
*div = value;
default:
break;
}
}
/*
* Extra anal debugging.
*/
if (netDFDebug == NET_DF_DEBUG_ON) {
for (n = 0; n < numBytes; n++) {
if (startPtr[n] != destPtr[n]) {
printf("DEC FDDI: NetDFBcopy failed!\n");
DBG_CALL;
Mach_EmptyWriteBuffer();
Mach_EmptyWriteBuffer();
Mach_EmptyWriteBuffer();
Mach_EmptyWriteBuffer();
return;
}
}
}
}
/*
*----------------------------------------------------------------------
*
* OutputXmtElement --
*
* Transmit the given packet that was waiting on the transmit
* queue. The element is removed from the queue.
*
* Results:
* SUCCESS if the packet was successfully transmitted; FAILURE
* otherwise.
*
* Side effects:
* A packet is output.
*
*----------------------------------------------------------------------
*/
OutputXmtElement(statePtr, xmtElementPtr)
register NetDFState *statePtr;
register NetDFXmtElement *xmtElementPtr;
{
int status;
switch(xmtElementPtr->xmtType) {
case NET_DF_XMT_HOST:
DFprintf("DEC FDDI: Outputting LLC packet.\n");
status = OutputPacket(xmtElementPtr->fddiHdrPtr,
xmtElementPtr->scatterGatherPtr,
xmtElementPtr->scatterGatherLength,
statePtr);
DFprintf("DEC FDDI: Finished outputting LLC packet.\n");
break;
case NET_DF_XMT_SMT:
status = NetDFOutputSmtPacket(statePtr,
xmtElementPtr->smtDescPtr);
break;
default:
printf("DEC FDDI: Unknown XMT element packet type.\n");
status = FAILURE;
break;
}
List_Move((List_Links *) xmtElementPtr,
LIST_ATREAR(statePtr->xmitFreeList));
return status;
}
/*
*----------------------------------------------------------------------
*
* CastOffPacket --
*
* Given pointers to the first and last RMC XMT descriptors,
* transfer ownerships of those descriptors to the adapter
* and tell it to start transmitting those descriptors.
*
* Results:
* FAILURE if something went wrong.
*
* Side effects:
* The adapter will start transmitting.
*
*----------------------------------------------------------------------
*/
static void
CastOffPacket(statePtr, firstDescPtr, lastDescPtr)
register NetDFState *statePtr;
register volatile NetDFRmcXmtDesc *firstDescPtr;
register volatile NetDFRmcXmtDesc *lastDescPtr;
{
register volatile NetDFRmcXmtDesc *descPtr;
unsigned long own;
descPtr = lastDescPtr;
/*
* Give the buffers used to the adapter. Avoid race conditions
* by starting with the last RMC XMT buffer and ending with
* the first.
*/
while (TRUE) {
descPtr->own = NET_DF_RMC_ADAPTER_OWN;
if (descPtr == firstDescPtr) {
break;
}
descPtr = PREV_RMC_SEND(descPtr);
}
/*
* Due to pipelineing in the adapter, we must read the own bit back
* on the first descriptor to ensure that it was placed there.
*/
own = descPtr->own;
if ((own & NET_DF_RMC_OWN) == NET_DF_RMC_HOST_OWN) {
MAKE_NOTE("host owns RMC XMT descriptor!");
}
/*
* Give the adapter a little kick.
*/
*(statePtr->regCtrlA) |= NET_DF_CTRLA_XMT_POLL_DEMAND;
Mach_EmptyWriteBuffer();
statePtr->stats.packetsQueued++;
return;
}
/*
*----------------------------------------------------------------------
*
* NetDFXmitInit --
*
* Initialize the transmission queue structures. This includes setting
* up the transmission ring buffers.
*
* Results:
* None.
*
* Side effects:
* The transmission ring is initialized.
*
*----------------------------------------------------------------------
*/
void
NetDFXmitInit(statePtr)
register NetDFState *statePtr; /* State of the interface. */
{
if (!statePtr->xmitMemAllocated) {
/*
* SMT XMT ring
*/
statePtr->smtXmtFirstDescPtr = (NetDFSmtXmtDesc *)
(statePtr->initComPtr->smtXmtBase + statePtr->slotAddr);
/*
* RMC XMT ring
*/
statePtr->rmcXmtFirstDescPtr = (NetDFRmcXmtDesc *)
(statePtr->initComPtr->rmcXmtBase + statePtr->slotAddr);
statePtr->xmitMemAllocated = TRUE;
}
/*
* Reset the SMT and RMC XMT ring pointers.
*/
statePtr->smtXmtNextDescPtr = statePtr->smtXmtFirstDescPtr;
statePtr->smtXmtLastDescPtr = statePtr->smtXmtFirstDescPtr +
(statePtr->initComPtr->smtXmtEntries - 1);
statePtr->rmcXmtNextDescPtr = statePtr->rmcXmtFirstDescPtr;
statePtr->rmcXmtLastDescPtr = statePtr->rmcXmtFirstDescPtr +
(statePtr->initComPtr->rmcXmtEntries - 1);
statePtr->xmitMemInitialized = TRUE;
return;
}
/*
*----------------------------------------------------------------------
*
* NetDFOutputSmtPacket --
*
* Transfer an SMT packet from the SMT XMT ring and place it
* onto the RMC XMT ring.
*
* Results:
* FAILURE if something went wrong.
*
* Side effects:
* Transmit ring is modified to contain the SMT packet.
*
*----------------------------------------------------------------------
*/
ReturnStatus
NetDFOutputSmtPacket(statePtr, smtDescPtr)
register NetDFState *statePtr;
register volatile NetDFSmtXmtDesc *smtDescPtr;
{
register volatile NetDFRmcXmtDesc *descPtr;
register volatile NetDFRmcXmtBuf *rmcBufPtr;
register unsigned char *smtBufPtr;
register int length;
descPtr = statePtr->rmcXmtNextDescPtr;
/*
* Do some sanity checks. Why the polarity of the own bits on the
* two buffers are different, I don't know.
*/
if ((descPtr->own & NET_DF_RMC_OWN) == NET_DF_RMC_ADAPTER_OWN) {
printf("DEC FDDI: RMC transmit buffer owned by adapter in SMT XMT.\n");
return (FAILURE);
}
if ((smtDescPtr->own & NET_DF_OWN) == NET_DF_ADAPTER_OWN) {
printf("DEC FDDI: SMT transmit buffer owned by adapter in SMT XMT.\n");
return (FAILURE);
}
statePtr->transmitting = TRUE;
statePtr->hostTransmit = FALSE;
statePtr->curScatGathPtr = (Net_ScatterGather *)NIL;
statePtr->curSmtXmtDescPtr = smtDescPtr;
rmcBufPtr = RmcXmtBufFromDesc(statePtr, descPtr);
smtBufPtr = (unsigned char *)
(statePtr->slotAddr + (unsigned long)(smtDescPtr->bufAddr));
length = smtDescPtr->pbc;
/*
* Transfer the data from the SMT XMT ring to the RMC XMT ring.
*/
descPtr->rmcXmtDesc = NET_DF_RMC_XMT_FIRST_PAGE | (unsigned long)length;
while (length > 0) {
if (length < NET_DF_RMC_XMT_BUF_SIZE) {
NetDFBcopy(smtBufPtr, rmcBufPtr, length);
break;
} else {
NetDFBcopy(smtBufPtr, rmcBufPtr, NET_DF_RMC_XMT_BUF_SIZE);
length -= NET_DF_RMC_XMT_BUF_SIZE;
smtBufPtr += NET_DF_RMC_XMT_BUF_SIZE;
descPtr = NEXT_RMC_SEND(descPtr);
descPtr->rmcXmtDesc = NET_DF_RMC_XMT_MIDDLE_PAGE;
rmcBufPtr = RmcXmtBufFromDesc(statePtr, descPtr);
}
}
descPtr->rmcXmtDesc |= NET_DF_RMC_XMT_LAST_PAGE;
MAKE_NOTE("begin transmitting SMT packet.");
CastOffPacket(statePtr, statePtr->rmcXmtNextDescPtr, descPtr);
return(SUCCESS);
}
/*
*----------------------------------------------------------------------
*
* OutputPacket --
*
* Assemble and output the packet in the given scatter/gather element.
* The FDDI header contains the address of the destination host
* and the higher level protocol type already.
*
* Results:
* FAILURE if something went wrong.
*
* Side effects:
* Transmit command list is modified to contain the packet.
*
*----------------------------------------------------------------------
*/
static ReturnStatus
OutputPacket(fddiHdrPtr, scatterGatherPtr, scatterGatherLength, statePtr)
Net_FDDIHdr *fddiHdrPtr; /* FDDI header of packet */
register Net_ScatterGather *scatterGatherPtr; /* Data portion of packet */
int scatterGatherLength; /* Length of data portion
* gather array. */
register NetDFState *statePtr; /* The interface state. */
{
register volatile NetDFRmcXmtDesc *descPtr;
register volatile unsigned char *descBufPtr;
register Address bufPtr;
register int bufCount;
register int length;
register int remaining;
int totalLength;
int i, n, l;
descPtr = statePtr->rmcXmtNextDescPtr;
/*
* Do some sanity checks.
*/
if ((descPtr->own & NET_DF_RMC_OWN) == NET_DF_RMC_ADAPTER_OWN) {
printf("DEC FDDI: Transmit buffer owned by adapter.\n");
return (FAILURE);
}
statePtr->transmitting = TRUE;
statePtr->hostTransmit = TRUE;
statePtr->curScatGathPtr = scatterGatherPtr;
/*
* Total up the size of the packet. Do a sanity check to make sure
* that the packet is not too large, and then make sure that we
* own enough RMC XMT descriptors to dump the packet into.
*/
totalLength = NET_DF_RMC_XMT_BUF_HDR_SIZE;
for (i = 0; i < scatterGatherLength; i++) {
totalLength += scatterGatherPtr[i].length;
}
if (totalLength > NET_DF_MAX_PACKET_SIZE) {
printf("DEC FDDI: OutputPacket: packet too large (%d)\n", totalLength);
return FAILURE;
}
i = (totalLength / NET_DF_RMC_XMT_BUF_SIZE);
n = statePtr->rmcXmtLastDescPtr - statePtr->rmcXmtFirstDescPtr;
l = descPtr - statePtr->rmcXmtFirstDescPtr;
descPtr = statePtr->rmcXmtFirstDescPtr + ((i + l) % (n + 1));
if ((descPtr->own & NET_DF_RMC_OWN) == NET_DF_RMC_ADAPTER_OWN) {
printf("DEC FDDI: Last transmit buffer owned by adapter.\n");
return (FAILURE);
}
/*
* Set up the header.
*/
descPtr = statePtr->rmcXmtNextDescPtr;
descBufPtr = (unsigned char *)RmcXmtBufFromDesc(statePtr, descPtr);
fddiHdrPtr->prh[0] = NET_DF_PRH0;
fddiHdrPtr->prh[1] = NET_DF_PRH1;
fddiHdrPtr->prh[2] = NET_DF_PRH2;
NET_FDDI_ADDR_COPY(statePtr->fddiAddress, fddiHdrPtr->source);
NetDFBcopy(fddiHdrPtr, descBufPtr, sizeof(Net_FDDIHdr));
descBufPtr += sizeof(Net_FDDIHdr);
/*
* Transfer the scatter/gather array to the RMC XMT ring.
*/
descPtr->rmcXmtDesc = NET_DF_RMC_XMT_FIRST_PAGE | totalLength;
remaining = NET_DF_RMC_XMT_BUF_SIZE - sizeof(Net_FDDIHdr);
for (bufCount = 0; bufCount < scatterGatherLength;
bufCount++, scatterGatherPtr++ ) {
/*
* If it is an empty buffer then skip it.
*/
length = scatterGatherPtr->length;
if (length == 0) {
continue;
}
bufPtr = scatterGatherPtr->bufAddr;
/*
* When the while loop exits, the current RMC XMT buffer will have
* enough space left in it to place what is left of the scatter
* gather array.
*/
while (length > remaining) {
/*
* Top off the current RMC XMT buffer.
*/
if (remaining > 0) {
NetDFBcopy(bufPtr, descBufPtr, remaining);
bufPtr += remaining;
length -= remaining;
}
/*
* Obtain and initialize the next RMC XMT buffer.
*/
descPtr = NEXT_RMC_SEND(descPtr);
if ((descPtr->own & NET_DF_RMC_OWN) ==
NET_DF_RMC_ADAPTER_OWN) {
printf("DEC FDDI: Transmit buffer owned by adapter.\n");
return (FAILURE);
}
descPtr->rmcXmtDesc = NET_DF_RMC_XMT_MIDDLE_PAGE;
descBufPtr = (unsigned char *)RmcXmtBufFromDesc(statePtr, descPtr);
remaining = NET_DF_RMC_XMT_BUF_SIZE;
}
/*
* length <= remaining
*/
NetDFBcopy(bufPtr, descBufPtr, length);
remaining -= length;
descBufPtr += length;
/*
* We've used up the current scatter gather. Get the next.
* If remaining == 0, then the above while loop will initialize
* another RMC XMT buffer and descriptor
*/
}
/*
* Upon exit of the for-loop, descPtr points to the last RMC XMT
* buffer used. Change the descriptor to be an EOP descriptor.
*/
descPtr->rmcXmtDesc |= NET_DF_RMC_XMT_LAST_PAGE;
CastOffPacket(statePtr, statePtr->rmcXmtNextDescPtr, descPtr);
MAKE_NOTE("finished casting off HOST packet.");
return(SUCCESS);
}
/*
*----------------------------------------------------------------------
*
* NetDFXmitDone --
*
* This routine will process a completed transmit command. It will
* check for errors and update the transmission ring pointers.
*
* Results:
* FAILURE if problem is found.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
ReturnStatus
NetDFXmitDone(statePtr)
register NetDFState *statePtr; /* State of the interface */
{
register volatile NetDFRmcXmtDesc *descPtr;
register NetDFXmtElement *xmitElementPtr;
register Net_FDDIStats *stats;
register int size;
ReturnStatus status;
descPtr = statePtr->rmcXmtNextDescPtr;
stats = &statePtr->stats;
/*
* If there is nothing that is currently being sent then something is
* wrong.
*/
if ((statePtr->hostTransmit == TRUE) &&
(statePtr->curScatGathPtr == (Net_ScatterGather *) NIL)) {
printf( "DEC FDDI: NetDFXmitDone: No current packet\n.");
status = FAILURE;
goto exit;
}
/*
* Check for errors.
*/
if ((descPtr->own & NET_DF_RMC_OWN) == NET_DF_RMC_ADAPTER_OWN) {
printf("DEC FDDI: Bogus XMT interrupt. Buffer owned by adapter.\n");
status = FAILURE;
goto exit;
}
if (!(descPtr->rmcXmtDesc & NET_DF_RMC_XMT_SOP)) {
printf("DEC FDDI: Bogus XMT interrupt. Buffer not start of packet\n");
status = FAILURE;
goto exit;
}
if ((descPtr->rmcXmtDesc & NET_DF_RMC_XMT_DCC) != NET_DF_DCC_SUCCESS) {
printf("DEC FDDI: Unsuccessful completion code: 0x%x",
descPtr->rmcXmtDesc & NET_DF_RMC_XMT_DCC);
return (FAILURE);
}
/*
* Traverse the packet.
*/
while (TRUE) {
if (descPtr->rmcXmtDesc & NET_DF_RMC_XMT_EOP) {
break;
}
descPtr = NEXT_RMC_SEND(descPtr);
if (descPtr == statePtr->rmcXmtNextDescPtr) {
panic("DEC FDDI: Transmit ring with no end of packet.\n");
}
if ((descPtr->rmcXmtDesc & NET_DF_RMC_OWN) ==
NET_DF_RMC_ADAPTER_OWN) {
printf("DEC FDDI: XMT done: buffer owned by adapter.\n");
status = FAILURE;
goto exit;
}
}
/*
* Collect some stats.
*/
stats->packetsSent++;
size = statePtr->rmcXmtNextDescPtr->rmcXmtDesc & NET_DF_RMC_XMT_PBC;
stats->bytesSent += size;
stats->transmitHistogram[size >> NET_FDDI_STATS_HISTO_SHIFT]++;
/*
* Update the ring pointer to point at the next buffer to use.
*/
statePtr->rmcXmtNextDescPtr = NEXT_RMC_SEND(descPtr);
if (statePtr->hostTransmit == TRUE) {
/*
* Mark the packet as done.
*/
MAKE_NOTE("finished transmitting HOST packet.");
statePtr->curScatGathPtr->done = TRUE;
if (statePtr->curScatGathPtr->mutexPtr != (Sync_Semaphore *) NIL) {
MAKE_NOTE("waking up process waiting for transmit to finish.");
NetOutputWakeup(statePtr->curScatGathPtr->mutexPtr);
}
} else {
MAKE_NOTE("finished transmitting SMT packet.");
}
/*
* If there are more packets to send then send the first one on
* the queue. Otherwise there is nothing being transmitted.
*/
status = SUCCESS;
if (statePtr->resetPending == TRUE) {
goto exit;
}
if (!List_IsEmpty(statePtr->xmitList)) {
xmitElementPtr = (NetDFXmtElement *) List_First(statePtr->xmitList);
status = OutputXmtElement(statePtr, xmitElementPtr);
} else {
statePtr->transmitting = FALSE;
statePtr->curScatGathPtr = (Net_ScatterGather *) NIL;
}
exit:
/*
* This assumes that whatever calls us will reset the chip if we return
* anything other than SUCCESS. This way we avoid resetting the chip
* twice in a row.
*/
if ((statePtr->resetPending == TRUE) && (status == SUCCESS)) {
statePtr->transmitting = FALSE;
NetDFRestart(statePtr->interPtr);
}
if (status != SUCCESS) {
statePtr->transmitting = FALSE;
}
return status;
}
/*
*----------------------------------------------------------------------
*
* NetDFOutput --
*
* Output a packet. The procedure is to either put the packet onto the
* queue of outgoing packets if packets are already being sent, or
* otherwise to send the packet directly.
*
* Results:
* SUCCESS if the packet was sent or queued successfully, otherwise
* FAILURE.
*
* Side effects:
* Queue of packets modified.
*
*----------------------------------------------------------------------
*/
/*ARGSUSED*/
ReturnStatus
NetDFOutput(interPtr, hdrPtr, scatGathPtr, scatGathLength, rpc, statusPtr)
Net_Interface *interPtr; /* The network interface. */
Address hdrPtr; /* Packet header. */
register Net_ScatterGather *scatGathPtr; /* Data portion of packet. */
register int scatGathLength; /* Length of data portion
* gather array. */
Boolean rpc; /* An RPC packet? */
ReturnStatus *statusPtr; /* Status from sending
* packet.*/
{
register NetDFState *statePtr;
register NetDFXmtElement *xmitPtr;
Net_FDDIHdr *fddiHdrPtr = (Net_FDDIHdr *)hdrPtr;
Boolean restart = FALSE;
ReturnStatus status;
statePtr = (NetDFState *) interPtr->interfaceData;
MASTER_LOCK(&interPtr->mutex);
if (statePtr->flags & NET_DF_FLAGS_RESETTING) {
MAKE_NOTE("Process waiting in NetDFOutput while resetting.\n");
do {
Sync_MasterWait(&statePtr->doingReset, &interPtr->mutex, FALSE);
} while (statePtr->flags & NET_DF_FLAGS_RESETTING);
}
/*
* See if the packet is for us. In this case just copy in the packet
* and call the higher level routine.
*/
if (!Net_FDDIAddrCmp(statePtr->fddiAddress, fddiHdrPtr->dest)) {
int i, length;
length = sizeof(Net_FDDIHdr);
for (i = 0; i < scatGathLength; i++) {
length += scatGathPtr[i].length;
}
if (length <= NET_DF_MAX_PACKET_SIZE) {
register Address bufPtr;
MAKE_NOTE("--- Loopback buffer used ---");
NET_FDDI_ADDR_COPY(statePtr->fddiAddress, fddiHdrPtr->source);
bufPtr = (Address)statePtr->loopBackBuffer;
bcopy((Address)fddiHdrPtr, bufPtr, sizeof(Net_FDDIHdr));
bufPtr += sizeof(Net_FDDIHdr);
Net_GatherCopy(scatGathPtr, scatGathLength, bufPtr);
Net_Input(interPtr, (Address)statePtr->loopBackBuffer, length);
}
scatGathPtr->done = TRUE;
status = SUCCESS;
if (statusPtr != (ReturnStatus *) NIL) {
*statusPtr = SUCCESS;
}
goto exit;
}
/*
* If no packet is being sent then go ahead and send this one.
*/
if (!statePtr->transmitting) {
status = OutputPacket(fddiHdrPtr, scatGathPtr,
scatGathLength, statePtr);
if (status != SUCCESS) {
restart = TRUE;
} else if (statusPtr != (ReturnStatus *) NIL) {
*statusPtr = SUCCESS;
}
goto exit;
}
/*
* There is a packet being sent so this packet has to be put onto the
* transmission queue. Get an element off of the transmission free list.
* If none available then drop the packet.
*/
if (List_IsEmpty(statePtr->xmitFreeList)) {
statePtr->stats.xmtPacketsDropped++;
scatGathPtr->done = TRUE;
status = FAILURE;
goto exit;
}
xmitPtr = (NetDFXmtElement *)
List_First((List_Links *) statePtr->xmitFreeList);
List_Remove((List_Links *) xmitPtr);
/*
* Initialize the list element and place on the queue.
*/
xmitPtr->fddiHdrPtr = fddiHdrPtr;
xmitPtr->scatterGatherPtr = scatGathPtr;
xmitPtr->scatterGatherLength = scatGathLength;
xmitPtr->xmtType = NET_DF_XMT_HOST;
List_Insert((List_Links *) xmitPtr, LIST_ATREAR(statePtr->xmitList));
if (statusPtr != (ReturnStatus *) NIL) {
*statusPtr = SUCCESS;
}
status = SUCCESS;
exit:
MASTER_UNLOCK(&interPtr->mutex);
if (restart) {
Net_DFRestart(interPtr);
}
return status;
}
/*
*----------------------------------------------------------------------
*
* NetDFSmtOutput --
*
* Transfer a packet from the SMT XMT ring to the RMC XMT ring.
* If a packet is currently being sent, then the SMT packet is
* placed on the transmit queue; otherwise, it is sent directly.
*
* Results:
* SUCCESS if the packet was sent or queued successfully, FAILURE
* otherwise.
*
* Side effects:
* Queue of packets modified.
*
*----------------------------------------------------------------------
*/
ReturnStatus
NetDFSmtOutput(interPtr)
Net_Interface *interPtr;
{
register NetDFState *statePtr;
register NetDFXmtElement *xmitPtr;
ReturnStatus status;
Boolean restart = FALSE;
statePtr = (NetDFState *)interPtr->interfaceData;
/*
* If no packet is being sent then go ahead and send this one.
*/
if (!statePtr->transmitting) {
status = NetDFOutputSmtPacket(statePtr, statePtr->smtXmtNextDescPtr);
if (status != SUCCESS) {
restart = TRUE;
}
goto exit;
}
/*
* There is a packet being sent so this packet has to be put onto the
* transmission queue. Get an element off of the transmission free list.
* If none available then drop the packet.
*/
if (List_IsEmpty(statePtr->xmitFreeList)) {
statePtr->stats.xmtPacketsDropped++;
status = FAILURE;
goto exit;
}
xmitPtr = (NetDFXmtElement *)
List_First((List_Links *) statePtr->xmitFreeList);
List_Remove((List_Links *) xmitPtr);
/*
* Initialize the list element.
*/
xmitPtr->fddiHdrPtr = NULL;
xmitPtr->scatterGatherPtr = NULL;
xmitPtr->scatterGatherLength = 0;
xmitPtr->smtDescPtr = statePtr->smtXmtNextDescPtr;
xmitPtr->xmtType = NET_DF_XMT_SMT;
statePtr->smtXmtNextDescPtr = NEXT_SMT_SEND(statePtr->smtXmtNextDescPtr);
/*
* Put onto the transmission queue.
*/
List_Insert((List_Links *) xmitPtr, LIST_ATREAR(statePtr->xmitList));
status = SUCCESS;
exit:
if (restart) {
NetDFRestart(interPtr);
}
return SUCCESS;
}
/*
*----------------------------------------------------------------------
*
* NetDFXmitDrop --
*
* Drop the current packet. Called at the beginning of the
* restart sequence, before curScatGathPtr is reset to NIL.
*
* Results:
* None.
*
* Side effects:
* Current scatter gather pointer is reset and processes waiting
* for synchronous output are notified.
*
*----------------------------------------------------------------------
*/
void
NetDFXmitDrop(statePtr)
register NetDFState *statePtr; /* State of the interface. */
{
MAKE_NOTE("Dropping current packet.");
if (statePtr->curScatGathPtr != (Net_ScatterGather *) NIL) {
statePtr->curScatGathPtr->done = TRUE;
if (statePtr->curScatGathPtr->mutexPtr != (Sync_Semaphore *) NIL) {
NetOutputWakeup(statePtr->curScatGathPtr->mutexPtr);
}
statePtr->curScatGathPtr = (Net_ScatterGather *) NIL;
}
statePtr->transmitting = FALSE;
return;
}
/*
*----------------------------------------------------------------------
*
* NetDFXmitRestart --
*
* Restart transmission of packets at the end of the restart
* sequence, after a chip reset.
*
* Results:
* None.
*
* Side effects:
* Output queue started up.
*
*----------------------------------------------------------------------
*/
void
NetDFXmitRestart(statePtr)
register NetDFState *statePtr; /* State of the interface. */
{
register NetDFXmtElement *xmitElementPtr;
ReturnStatus status;
/*
* Start output if there are any packets queued up.
*/
if (!List_IsEmpty(statePtr->xmitList)) {
xmitElementPtr = (NetDFXmtElement *) List_First(statePtr->xmitList);
status = OutputXmtElement(statePtr, xmitElementPtr);
List_Move((List_Links *) xmitElementPtr,
LIST_ATREAR(statePtr->xmitFreeList));
/*
* If we cannot successfully output the packet, then flush the
* transmit queue.
*/
if (status != SUCCESS) {
printf("DEC FDDI: Cannot output first packet on restart.\n");
NetDFXmitFlushQ(statePtr);
}
} else {
statePtr->transmitting = FALSE;
statePtr->curScatGathPtr = (Net_ScatterGather *) NIL;
}
return;
}
/*
*----------------------------------------------------------------------
*
* NetDFXmitFlushQ --
*
* Drop all packets in the transmit queue.
*
* Results:
* None.
*
* Side effects:
* Processes waiting for synchronous output are notified.
*
*----------------------------------------------------------------------
*/
void
NetDFXmitFlushQ(statePtr)
register NetDFState *statePtr; /* State of the interface. */
{
register NetDFXmtElement *xmtElementPtr;
while (TRUE) {
if (List_IsEmpty(statePtr->xmitList)) {
break;
}
xmtElementPtr = (NetDFXmtElement *) List_First(statePtr->xmitList);
switch(xmtElementPtr->xmtType) {
case NET_DF_XMT_HOST:
xmtElementPtr->scatterGatherPtr->done = TRUE;
if (xmtElementPtr->scatterGatherPtr->mutexPtr !=
(Sync_Semaphore *) NIL) {
NetOutputWakeup(xmtElementPtr->scatterGatherPtr->mutexPtr);
}
break;
case NET_DF_XMT_SMT:
default:
break;
}
List_Move((List_Links *) xmtElementPtr,
LIST_ATREAR(statePtr->xmitFreeList));
}
}